const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`; // 标签名匹配
const qnameCapture = `((?:${ncname}\\:)?${ncname})`; // 带命名空间的标签名 比如 svg:path
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 匹配开始标签的开头部分，比如 <div、<svg:path。
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配结束标签，比如 </div>。
// 匹配标签中的属性名和属性值，支持双引号、单引号和无引号三种属性值写法。
const attribute =
  /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
const startTagClose = /^\s*(\/?)>/; // <input /> 匹配 />
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g; // {{ message }}

// 创建ast语法树
function createASTElement(tag, attrs) {
  return {
    tag,
    attrs,
    children: [],
    type: 1,
    parent: null,
  };
}
let root; //根元素
let createParent; // 当前元素的父亲
//数据结构 栈
let stack = [];

// 开始标签
function start(tag, attrs) {
  const element = createASTElement(tag, attrs);
  if (!root) {
    root = element;
  }
  createParent = element;
  // 入栈
  stack.push(element);
}
// 文本
function charts(text) {
  // 去除空格
  text = text.replace(/s/g, "");
  if (text) {
    createParent.children.push({
      type: 3,
      text,
    });
  }
}

// 结束标签
function end(tag) {
  const element = stack.pop();
  createParent = stack[stack.length - 1];
  if (createParent) {
    //元素闭合
    element.parent = createParent.tag;
    createParent.children.push(element);
  }
}

export function parseHtml(html) {
  // <div id="app"> hello{{msg}}  <h></h> </div>
  while (html) {
    let textEnd = html.indexOf("<");
    if (textEnd === 0) {
      // 开始标签
      const startTagMatch = parseStartTag();
      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs);

      }
      // 结束标签
      const endTagMatch = html.match(endTag);
      if (endTagMatch) {
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);

      }
    } else if (textEnd > 0) {
      // 文本
      // 获取文本内容
      let text = html.substring(0, textEnd);
      if (text) {
        advance(text.length);
        charts(text);
      }
    }
  }

  function parseStartTag() {
    const start = html.match(startTagOpen);
    if (start) {
      // 创建ast语法树
      const match = {
        tagName: start[1],
        attrs: [],
      };
      // 删除开始标签
      advance(start[0].length);
      let attr;
      let end;
      // 开始标签结束里的属性
      while (
        !(end = html.match(startTagClose)) &&
        (attr = html.match(attribute))
      ) {
        match.attrs.push({
          name: attr[1],
          value: attr[3] || attr[4] || attr[5],
        });
        advance(attr[0].length);
      }
      if (end) {
        // 删除开始标签的 '>'
        advance(end[0].length);
        return match;
      }
    }
  }
  function advance(n) {
    html = html.substring(n);
  }
  return root;
}